// ScenarioCreationState.cpp: implementation of the ScenarioCreationState class.
//
//////////////////////////////////////////////////////////////////////

#include "ScenarioCreationState.h"
#include "NewScenarioState.h"
#include "LoadScenarioState.h"

#include <stdio.h>
#include <stdlib.h>

#ifdef FREEGLUT_IS_PRESENT
#  include <GL/freeglut.h>
#else
#  ifdef __APPLE__
#    include <GLUT/glut.h>
#  else
#    include <GL/glut.h>
#  endif
#endif

/* Application Includes*/
#include "Scenegraph.h"
#include "Camera.h"
#include "FPSTest.h"
#include "CPUTest.h"
#include "GUI.h"
#include "ObjectList.h"
#include "Land.h"
#include "Keyboard.h"
#include "Mouse.h"
#include "MapImage.h"
#include "Movie.h"
#include "Waypoint.h"

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

ScenarioCreationState::ScenarioCreationState(State* os,LoadingInfo* li,int backTo)
{
ck = new ulClock;
float dt = 0.0f;
bool canceled = false;
v = 1;

this->backTo = backTo;

renameScenarioFile(li);

this->info = li;

this->wireframe = 0;

/* TRIAL */
ls = NULL;
/**/

inner_state = EDITING_STATE;

this->oldState = os;

int wh = (float)glutGet ( (GLenum) GLUT_WINDOW_HEIGHT ) ;
int ww = (float)glutGet ( (GLenum) GLUT_WINDOW_WIDTH  ) ;

fps = new FPSTest();
sprintf(fps_text_legend,"FPS : ---\n");
fps_text = new puText ( (int)(0.90 * (float)ww) , (int)(0.03 * (float)wh) );
fps_text -> setLabel(fps_text_legend);
fps_text -> setColour		 ( PUCOL_LABEL, 0.7f,0.8f,0.1f,1.0f ) ;

current_map_widget = 0;
//mapsWidget = (MapImage**) malloc( NUM_MAP_WIDGETS * sizeof(MapImage*) );

this->gui = new GUI(this,li);

/* Other stuff */
this->kb = new Keyboard();
this->ms = new Mouse();

this->camera = new Camera();

this->scene = new Scenegraph(li,camera);

int lt;

doCritical(lt = li->loadingType, li->cs);

if(lt == LOAD)
	{
	// load objects
	this->loadScenario();
	}

this->nextState = this;

doCritical(canceled = li->canceled;
		   this->oldState = li->old_s,
	       li->cs);


/* Create Camera */
ck->update();
dt = ck->getDeltaTime();

doCritical(li->scenarioProgress = CAMERA_PROGRESS;
		   canceled = li->canceled 
		   , li->cs);

l = new Land(li->dem_filename,li->obj_filename,li);

mapsWidget[0] = new MapImage(l->getLevelsMatrix(),l->getHeigth(),l->getWidth(),0.01f,0.01f,0.3f,0.2f);
mapsWidget[1] = new MapImage(l->getExpoMatrix(),l->getHeigth(),l->getWidth(),0.01f,0.01f,0.3f,0.2f);
mapsWidget[2] = new MapImage(l->getShadowMatrix(),l->getHeigth(),l->getWidth(),0.01f,0.01f,0.3f,0.2f);

scene->addLand(l);
scene->load();

scene->addWaypoints(li->wpn_filename);
scene->addMovie(li->cmv_filename);//"C:/Documents and Settings/Giorgio/Documenti/MSA/8/mondole.cmv");//li->mov_filename);

gui->setCorrection(-l->getXCorrection(),-l->getYCorrection());
// Destroy all matrices
l->freeAllMatrix();

  /*
    Set up the Sun.
  */

  sgVec3 sunposn ;
  sgSetVec3 ( sunposn, 0.2f, -0.5f, 0.5f ) ;
  ssgGetLight ( 0 ) -> setPosition ( sunposn ) ;

doCritical(
    li->scenarioProgress = 1.0f;
    li->completed = true;
	li->s = this, li->cs);

this->gui->show();
}

ScenarioCreationState::~ScenarioCreationState()
{
delete this->gui;
delete this->camera;
for(int i = 0; i < NUM_MAP_WIDGETS; i++) delete this->mapsWidget[i];
delete this->kb;
delete this->ms;
delete this->scene;
delete this->l;
delete this->ck;
delete this->fps;
puDeleteObject(fps_text);
}

void ScenarioCreationState::load(const char* filename)
{
}

void ScenarioCreationState::reset()
{
this->nextState = this;
}

void ScenarioCreationState::display(void)
{
glClearColor(0.0,0.2,0.7,1.0);
scene->display();

for(int i = 0; i < NUM_MAP_WIDGETS; i++)
	mapsWidget[current_map_widget]->display();

gui->display();

// display fps
sprintf(this->fps_text_legend,"FPS : %.1f",fps->test());
this->fps_text->setLegend(this->fps_text_legend);
puDisplay();
}

void ScenarioCreationState::resize(int w, int h)
{

}

void ScenarioCreationState::keyUp(unsigned char key, int x, int y)
{
kb->read(key,GLUT_UP,x,y);
}

void ScenarioCreationState::keyDown(unsigned char key, int x, int y)
{
kb->read(key,GLUT_DOWN,x,y);

if(inner_state == EDITING_STATE)
	editingKeyboard(key,x,y);
else if(inner_state == CAMERA_REPOSITIONING_STATE)
	cameraKeyboard(key,x,y);
else if(inner_state == MOVIE_STATE)
	movieKeyboard(key,x,y);
}

void ScenarioCreationState::editingKeyboard(unsigned char key, int x, int y)
{
if(key == 'w') 
	{
	wireframe = !wireframe;
	this->scene->setWireframe(wireframe);
	}
else if(key == 'm') 
	{
	if( mapsWidget[current_map_widget]->selected()) 
		{
		current_map_widget++; 
		if(current_map_widget >= NUM_MAP_WIDGETS) 
			{
			current_map_widget = 0;
			}
		}
	}
else if(key == 'h')
	{
	scene->updateObjectPosition(H_POSITION,45.0f);
	}
else if(key == 'H')
	{
	scene->updateObjectPosition(H_POSITION,-45.0f);
	}
else if(key == 'p')
	{
	scene->updateObjectPosition(P_POSITION,5.0f);
	}
else if(key == 'P')
	{
	scene->updateObjectPosition(P_POSITION,-5.0f);
	}
else if(key == 'r')
	{
	scene->updateObjectPosition(R_POSITION,5.0f);
	}
else if(key == 'R')
	{
	scene->updateObjectPosition(R_POSITION,-5.0f);
	}
else if(key == 'x')
	{
	scene->updateObjectPosition(Z_POSITION,0.5f);
	}
else if(key == 'X')
	{
	scene->updateObjectPosition(Z_POSITION,-0.5f);
	}
else if(key == 'c')
	{
	scene->switchToCameraRepositioningView();
	gui->switchToCameraRepositioningView();
	camera->switchToCameraRepositioningView();
	inner_state = CAMERA_REPOSITIONING_STATE;
	for(int i = 0; i < NUM_MAP_WIDGETS; i++)
		mapsWidget[current_map_widget]->hide();
	}
}

void ScenarioCreationState::movieKeyboard(unsigned char key, int x, int y)
{
if(key == 'q')
	{
	this->end();
	}
}

void ScenarioCreationState::cameraKeyboard(unsigned char key, int x, int y)
{
if(key == 'c')
	{
	scene->switchToEditingView();
	gui->switchToEditingView();
	camera->switchToEditingView();
	inner_state = EDITING_STATE;
	for(int i = 0; i < NUM_MAP_WIDGETS; i++)
		mapsWidget[current_map_widget]->reveal();
	}
}

void ScenarioCreationState::specialUp(int key, int x, int y)
{
kb->read(key+PU_KEY_GLUT_SPECIAL_OFFSET,GLUT_UP,x,y);
}

void ScenarioCreationState::specialDown(int key, int x, int y)
{
kb->read(key+PU_KEY_GLUT_SPECIAL_OFFSET,GLUT_DOWN,x,y);
}

void ScenarioCreationState::motion(int newx, int newy)
{
if(!this->gui->mouse(-1,-1,newx,newy) && !puMouse(newx,newy))
	{
	ls = ms->unproject(newx,newy,camera);
	//printf("%d %d\n",gui->getType(),gui->getKind());
	this->scene->showObject(ls,gui->getType(),gui->getKind());
	}

}

void ScenarioCreationState::passive(int newx, int newy)
{
if(!this->gui->mouse(-1,-1,newx,newy) && !puMouse(-1,-1,newx,newy))
	{
	ls = ms->unproject(newx,newy,camera);
	//printf("%d %d\n",gui->getType(),gui->getKind());
	this->scene->showObject(ls,gui->getType(),gui->getKind());
	}

for(int i = 0; i < NUM_MAP_WIDGETS; i++)
	mapsWidget[i]->mouse(-1,-1,newx,newy);
}

void ScenarioCreationState::mouse(int button, int state, int mouseX, int mouseY)
{
if( ((this->gui->mouse(button,state,mouseX,mouseY)) == 0) && !puMouse(button,state,mouseX,mouseY))
	{
	ls = ms->unproject(mouseX,mouseY,camera);
	if( (button == GLUT_LEFT_BUTTON) && (state == GLUT_DOWN)) 
		{
		this->scene->testLOS(ls,gui->getType(),gui->getKind());
		}
	else if( (button == GLUT_LEFT_BUTTON) && (state == GLUT_UP) )
		{
		this->scene->stopAction();
		}
	}

for(int i = 0; i < NUM_MAP_WIDGETS; i++)
	mapsWidget[i]->mouse(button,state,mouseX,mouseY);
}

State* ScenarioCreationState::idle(void)
{
if(kb->isPressed(27)) exit(0);

int i;

float hot = 0.0f;

if(inner_state == EDITING_STATE)
	{
	hot = this->scene->getHOT(this->camera->getCameraPosition()->xyz[SG_X],this->camera->getCameraPosition()->xyz[SG_Y]);
    
    if(kb->isPressed(GLUT_KEY_LEFT+PU_KEY_GLUT_SPECIAL_OFFSET))
    {
        if((mapsWidget[current_map_widget]->selected()))
        {
            for(i = 0; i < NUM_MAP_WIDGETS; i++)
            {
               mapsWidget[i]->moveLeft(1); 
            }
        }
        else
        {
            camera->move(TURN_LEFT,hot);
        }
    }
        
	if(kb->isPressed(GLUT_KEY_RIGHT+PU_KEY_GLUT_SPECIAL_OFFSET))
    {
        if((mapsWidget[current_map_widget]->selected()))
        {
            for(i = 0; i < NUM_MAP_WIDGETS; i++)
            {
                mapsWidget[i]->moveRight(1);
            }
        }
        else
        {
            camera->move(TURN_RIGHT,hot);
        }
    }
        
	if(kb->isPressed(GLUT_KEY_UP+PU_KEY_GLUT_SPECIAL_OFFSET))
    {
        if((mapsWidget[current_map_widget]->selected()))
        {
            for(i = 0; i < NUM_MAP_WIDGETS; i++)
            {
                mapsWidget[i]->moveUp(1);
            }
        }
        else
        {
            camera->move(LOOK_UP,hot);
        }
    }
        
	if(kb->isPressed(GLUT_KEY_DOWN+PU_KEY_GLUT_SPECIAL_OFFSET))
    {
        if((mapsWidget[current_map_widget]->selected()))
        {
            for(i = 0; i < NUM_MAP_WIDGETS; i++) mapsWidget[i]->moveDown(1);
        }
        else
        {
            camera->move(LOOK_DOWN,hot);
        }
    }
        
	if(kb->isPressed(GLUT_KEY_PAGE_UP+PU_KEY_GLUT_SPECIAL_OFFSET))
    {
        if((mapsWidget[current_map_widget]->selected()))
        {
            for(i = 0; i < NUM_MAP_WIDGETS; i++) mapsWidget[i]->zoomIn(1);
        }
        else
        {
            camera->move(GO_UP,hot);
        }
    }
        
	if(kb->isPressed(GLUT_KEY_PAGE_DOWN+PU_KEY_GLUT_SPECIAL_OFFSET))
    {
        if((mapsWidget[current_map_widget]->selected()))
        {
            for(i = 0; i < NUM_MAP_WIDGETS; i++) mapsWidget[i]->zoomOut(1);
        }
        else
        {
            camera->move(GO_DOWN,hot);
        }
    }
        
	if(kb->isPressed(GLUT_KEY_HOME+PU_KEY_GLUT_SPECIAL_OFFSET))
        if(!(mapsWidget[current_map_widget]->selected()))
            camera->move(RESET,hot);
        
	if(kb->isPressed('a'))					if(!(mapsWidget[current_map_widget]->selected())) camera->move(GO_AHEAD,hot);
	if(kb->isPressed('z'))					if(!(mapsWidget[current_map_widget]->selected())) camera->move(GO_BACKWARDS,hot);
	if(kb->isPressed('.'))					if(!(mapsWidget[current_map_widget]->selected())) camera->move(STRIFE_LEFT,hot);
	if(kb->isPressed(','))					if(!(mapsWidget[current_map_widget]->selected())) camera->move(STRIFE_RIGHT,hot);
	}
else if(inner_state == CAMERA_REPOSITIONING_STATE)
	{
	hot = this->scene->getHOT(this->camera->getMoviePosition()->xyz[SG_X],this->camera->getMoviePosition()->xyz[SG_Y]);
	if(kb->isPressed(GLUT_KEY_LEFT+PU_KEY_GLUT_SPECIAL_OFFSET))			  camera->move(TURN_LEFT,hot);
	if(kb->isPressed(GLUT_KEY_RIGHT+PU_KEY_GLUT_SPECIAL_OFFSET))		  camera->move(TURN_RIGHT,hot);
	if(kb->isPressed(GLUT_KEY_UP+PU_KEY_GLUT_SPECIAL_OFFSET))			  camera->move(LOOK_UP,hot);
	if(kb->isPressed(GLUT_KEY_DOWN+PU_KEY_GLUT_SPECIAL_OFFSET))			  camera->move(LOOK_DOWN,hot);
	if(kb->isPressed(GLUT_KEY_PAGE_UP+PU_KEY_GLUT_SPECIAL_OFFSET))		  camera->move(GO_UP,hot);
	if(kb->isPressed(GLUT_KEY_PAGE_DOWN+PU_KEY_GLUT_SPECIAL_OFFSET))	  camera->move(GO_DOWN,hot);
	if(kb->isPressed(GLUT_KEY_HOME+PU_KEY_GLUT_SPECIAL_OFFSET))			  camera->move(RESET,hot);;
	if(kb->isPressed('a'))											      camera->move(GO_AHEAD,hot);;
	if(kb->isPressed('z'))												  camera->move(GO_BACKWARDS,hot);;
	if(kb->isPressed('.'))												  camera->move(STRIFE_LEFT,hot);
	if(kb->isPressed(','))												  camera->move(STRIFE_RIGHT,hot);
	}
else if(inner_state == MOVIE_STATE)
	{
	this->scene->getMovie()->update();
	this->camera->setFilmPosition(this->scene->getMovie()->getLERPCameraPosition());
	}

// update GUI data display
this->gui->setData(this->camera->getCameraPosition(),hot,this->scene->getPointerPosition());

if(nextState == this) {return nextState;}
else {State* tmpState = nextState; this->reset(); return tmpState;}
}

void ScenarioCreationState::bindTextures()
{
for(int i = 0; i < NUM_MAP_WIDGETS; i++) mapsWidget[i]->bindTexture();
this->gui->bindTextures();
}

void ScenarioCreationState::createStates()
{
scene->createStates();
}

void ScenarioCreationState::goBack()
{
// return splashscreen state
this->nextState = oldState;
if(backTo == NEWSCENARIO)
	{
	NewScenarioState* nss = (NewScenarioState*) oldState;
	nss->reload();
	}
else if(backTo == LOADSCENARIO)
	{
	LoadScenarioState* lss = (LoadScenarioState*) oldState;
	lss->reload();
	}
}

void ScenarioCreationState::saveScenario()
{
FILE *scenario_file;
FILE *waypoint_file;
FILE *movie_file;

ObjectList *treeList = scene->getList(TREE_LIST);
ObjectList *buildingList = scene->getList(BUILDING_LIST);
ObjectList *textureList = scene->getList(TEXTURE_LIST);
ObjectList *facilityList = scene->getList(FACILITY_LIST);

if((scenario_file = fopen(scenario_file_name,"w")) != NULL)
	{
	fprintf(scenario_file,"%s\n",FILE_LIST_SECTION);
	fprintf(scenario_file,"%s\n",MAP_FILE_LIST);
	fprintf(scenario_file,"%s\n",dem_filename);
	fprintf(scenario_file,"%s\n",map_filename);
	fprintf(scenario_file,"%s\n",obj_filename);
	fprintf(scenario_file,"%s\n",tex_filename);
	fprintf(scenario_file,"%s\n",wpn_filename);
	fprintf(scenario_file,"%s\n",cmv_filename);
	fprintf(scenario_file,"%s\n",CAMERA_SECTION);
	saveCameraPosition(scenario_file);
	fprintf(scenario_file,"%s\n",OBJECT_LIST_SECTION);
	fprintf(scenario_file,"%s\n",TREES_LIST);
	treeList->fprint(scenario_file);
	fprintf(scenario_file,"%s\n",BUILDINGS_LIST);
	buildingList->fprint(scenario_file);
	fprintf(scenario_file,"%s\n",TEXTURES_LIST);
	textureList->fprint(scenario_file);	
	fprintf(scenario_file,"%s\n",FACILITIES_LIST);
	facilityList->fprint(scenario_file);
	fclose(scenario_file);
	}
else
	{
	printf("Cannot open %s scenario file for saving...\n",scenario_file_name);
	}

Waypoint *w = scene->getWaypoints();

if((waypoint_file  = fopen(wpn_filename,"w")) != NULL)
	{
	w->fprint(waypoint_file);
	fclose(waypoint_file);
	}
else
	{
	printf("Cannot open %s waypoint file for saving...\n",wpn_filename);
	}

Movie *m = scene->getMovie();

if((movie_file  = fopen(cmv_filename,"w")) != NULL)
	{
	m->fprint(movie_file);
	fclose(movie_file);
	}
else
	{
	printf("Cannot open %s movie file for saving...\n",cmv_filename);
	}

}

void ScenarioCreationState::saveCameraPosition(FILE* f)
{
fprintf(f,"%f %f %f %f %f %f\n",this->camera->getCameraPosition()->xyz[0] - this->l->getXCorrection(),this->camera->getCameraPosition()->xyz[1] - this->l->getYCorrection(), this->camera->getCameraPosition()->xyz[2], this->camera->getCameraPosition()->hpr[0], this->camera->getCameraPosition()->hpr[1], this->camera->getCameraPosition()->hpr[2]);
}

void ScenarioCreationState::renameScenarioFile(LoadingInfo* li)
{
doCritical(strcpy(scenario_file_name,li->dem_filename),li->cs);
doCritical(strcpy(dem_filename,li->dem_filename),li->cs);
doCritical(strcpy(obj_filename,li->obj_filename),li->cs);
doCritical(strcpy(tex_filename,li->tex_filename),li->cs);
doCritical(strcpy(map_filename,li->map_filename),li->cs);
doCritical(strcpy(wpn_filename,li->wpn_filename),li->cs);
doCritical(strcpy(cmv_filename,li->cmv_filename),li->cs);

int i = 0;
bool go = true;

while( go ) 
  {
  if( scenario_file_name[i]  == '.')
	{
	go = false;
	scenario_file_name[i+1] = 's';
	scenario_file_name[i+2] = 'n';
	scenario_file_name[i+3] = 'r';
	scenario_file_name[i+4] = '\0';
	}
  else if( scenario_file_name[i] == '\0')
	{
	go = false;
	}
  else
	{
	  i++;
	}
  }

doCritical(strcpy(li->snr_filename,scenario_file_name),li->cs);
}

void ScenarioCreationState::loadScenario()
{
FILE *scenario_file;
char string[1024];

ObjectList *treeList = scene->getList(TREE_LIST);
ObjectList *buildingList = scene->getList(BUILDING_LIST);
ObjectList *textureList = scene->getList(TEXTURE_LIST);
ObjectList *facilitiesList = scene->getList(FACILITY_LIST);

if((scenario_file = fopen(scenario_file_name,"r")) != NULL)
	{
	fgets(string,1024,scenario_file);
	fgets(string,1024,scenario_file);
	fgets(string,1024,scenario_file);
	fgets(string,1024,scenario_file);
	fgets(string,1024,scenario_file);
	fgets(string,1024,scenario_file);
	fgets(string,1024,scenario_file);
	fgets(string,1024,scenario_file);
	fgets(string,1024,scenario_file); // [CAMERA]
	loadCameraPosition(scenario_file); // camera data
	fgets(string,1024,scenario_file);
	fgets(string,1024,scenario_file);
	treeList->load(scenario_file);
	fgets(string,1024,scenario_file);
	buildingList->load(scenario_file);
	fgets(string,1024,scenario_file);
	textureList->load(scenario_file);
	fgets(string,1024,scenario_file);
	facilitiesList->load(scenario_file);
	fclose(scenario_file);
	}
else
	{
	printf("Cannot open %s for loading...\n",scenario_file_name);
	}
}

void ScenarioCreationState::loadCameraPosition(FILE* f)
{
float x,y,z,h,p,r;
char c; 
fscanf(f,"%f%f%f%f%f%f%c",&x,&y,&z,&h,&p,&r,&c); // camera data line
scene->setCameraStartPosition(x,y,z,h,p,r);
}

void ScenarioCreationState::start()
{
this->inner_state = MOVIE_STATE;
this->scene->switchToMovieView();
this->gui->switchToMovieView();
this->camera->switchToMovieView();
	for(int i = 0; i < NUM_MAP_WIDGETS; i++)
		mapsWidget[current_map_widget]->hide();
}

void ScenarioCreationState::end()
{
this->inner_state = EDITING_STATE;
this->scene->switchToEditingView();
this->gui->switchToEditingView();
this->camera->switchToEditingView();
	for(int i = 0; i < NUM_MAP_WIDGETS; i++)
		mapsWidget[current_map_widget]->reveal();
}

void ScenarioCreationState::play()
{
	this->scene->getMovie()->play();
}

void ScenarioCreationState::stop()
{
	this->scene->getMovie()->stop();
}

void ScenarioCreationState::forward()
{
	this->scene->getMovie()->forward();
}

void ScenarioCreationState::rewind()
{
	this->scene->getMovie()->rewind();
}
